package svc.elib.analysis;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;

import svc.elib.db.Author;
import svc.elib.db.Database;
import svc.elib.db.Paper;
import svc.elib.socnet.CentralityMetrics;
import svc.elib.socnet.Link;
import svc.elib.socnet.Net;
import svc.elib.socnet.SocConstructor;
import svc.elib.util.Distribution;

/**
 * Mining frequent collaborations
 * 
 * @author svc
 * @date 8.6.2013
 */
public class FrequentCollaborators {

	private Net net;
	private CentralityMetrics cm;
	
	class Collaboration implements Comparable<Collaboration> {
		Author a1;
		Author a2;
		int w;
		int firstYear;
		int lastYear;
		int span;
		LinkedList<Author> authorsInCommon;
		double betweeness;
		
		public Collaboration(Link l, double b) {
			LinkedList<Paper> papersInCommon = l.getPapersInCommon();
			a1 = l.getSrc();
			a2 = l.getDst();
			w = papersInCommon.size();
			firstYear = l.getFirstYear();
			lastYear = l.getLastYear();
			span = lastYear - firstYear + 1;
			authorsInCommon = determineAuthorsInCommon(a1, a2);
			betweeness = b;
		}

		@Override
		public int compareTo(Collaboration o) {
			return o.w - this.w;
		}
		
		public String headLine() {
			return "Collaborators, Weight, Span, AuthorsInCommon, firstYear, lastYear, A1Degree, A2Degree, Betweenness";
		}
		
		public String toString() {
			return "\"" + a1.getName() + "-" + a2.getName() + "\", " + w + ", " +
				   span + ", " + authorsInCommon.size() + ", " + firstYear + ", " + lastYear + ", " + 
				   net.getGraph().degree(a1) + ", " + net.getGraph().degree(a2) + ", " + betweeness;
		}
	}
	
	private LinkedList<Collaboration> collaborations = 
		new LinkedList<Collaboration>();
	
	public FrequentCollaborators(Net net) {
		this.net = net;
		determine();
	}
	
	private void determine() {
		cm = new CentralityMetrics(net);
		cm.computeBetweeness(false);
		
		Collection<Link> linkCol = net.getGraph().getEdges();
		Iterator<Link> linkIt = linkCol.iterator();
		while (linkIt.hasNext()) {
			Link l = linkIt.next();
			collaborations.add(new Collaboration(l, Math.round(cm.getLinkBetweenness(l.getName()))));
		}
		
		Collections.sort(collaborations);
	}
	
	private LinkedList<Author> determineAuthorsInCommon(Author a1, Author a2) {
		Collection<Author> a1Collaborators = net.getGraph().getNeighbors(a1);
		Collection<Author> a2Collaborators = net.getGraph().getNeighbors(a2);
		
		LinkedList<Author> authorsInCommon = new LinkedList<Author>();
		
		Iterator<Author> a1It = a1Collaborators.iterator();
		while (a1It.hasNext()) {
			Author a = a1It.next();
			if (a2Collaborators.contains(a)) {
				authorsInCommon.add(a);
			}
		}
		
		return authorsInCommon;
	}
	
	public void export(String outFile) 
		throws IOException
	{
		PrintWriter pw = new PrintWriter(
							new BufferedWriter(
									new FileWriter(outFile)));
		
		for (int i = 0; i < collaborations.size(); i++) {
			if (i == 0)
				pw.println(collaborations.get(i).headLine());
			
			pw.println(collaborations.get(i).toString());
		}
		
		pw.close();
		
		LinkedList<Integer> wData = new LinkedList<Integer>();
		LinkedList<Integer> sData = new LinkedList<Integer>();
		for (int i = 0; i < collaborations.size(); i++) {
			Collaboration c = collaborations.get(i);
			wData.add(c.w);
			sData.add(c.span);
		}
		
		System.out.println("\n\nDistribution of the collaboration weight");
		Distribution d = new Distribution(wData);
		d.printDistr();
		System.out.println("Complementary cummulative distribution... ");
		d.printComplementaryCumulative();
		
		System.out.println("\n\nDistribution of the collaboration span");
		d = new Distribution(sData);
		d.printDistr();
		System.out.println("Complementary cummulative distribution... ");
		d.printComplementaryCumulative();
	}
	
	public static void main(String[] args) 
		throws IOException
	{
		Database db = new Database("eLibData.csv", 1932, 2011);
		System.out.println(db.info());
		SocConstructor soc = new SocConstructor(db);
		Net net = soc.getNet();
		net.printInfo();
		
		FrequentCollaborators fs = new FrequentCollaborators(net);
		fs.export("results/FrequentCollaborators.csv");
	}
	
}
